﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Enter.Common;
using Enter.DataProxy.Cache.Configuration;
using System.Collections;
using Memcached.ClientLibrary;
using Enter.Common.Helper;

namespace Enter.DataProxy.Cache
{
    internal sealed class MemCache : ICacheService
    {

        #region 私有变量 装载初始化
        private static MemcachedClient cache;
        private static int _DEFAULT_MINUTES = 10;
        private static bool _enableCache = false;
        private static string _CacheName = string.Empty;
        private static string _Format_NAME = "Enter_{0}";
        private static bool _enableLog = false;

        public MemCache(bool isheard)
        {
            GetCurrentCache();
            if (_enableCache)
            {
                CheckError();
            }
        }

        private void GetCurrentCache()
        {


            CacheConfigurationManager MemManager = new CacheConfigurationManager();
            CacheSetting MemcachedSetting = MemManager.GetMemSetting();
            _enableCache = MemcachedSetting.EnableCaching;
            if (!_enableCache)
            {
                //表示无缓存模式
                LogHelper.LogInfo(string.Format("◆缓存基本配置 无缓存模式◆"));
            }
            else
            {
                _CacheName = MemcachedSetting.CacheName;
                _DEFAULT_MINUTES = MemcachedSetting.CachingTime;
                _enableLog = MemcachedSetting.EnableLog;

                string GetInstanceName = string.Format(_Format_NAME, _CacheName);
                if (_enableLog)
                {
                    LogHelper.LogInfo(string.Format("◆缓存基本配置开始 InstanceName:{0} ◆", GetInstanceName));
                }
                Disconnect();
                //ShutdownCache();



                string[] serverlist = new string[MemcachedSetting.CacheServers.Count];

                int i = 0;
                foreach (CacheServer server in MemcachedSetting.CacheServers)
                {
                    serverlist[i++] = server.HostName + ":" + server.CachePort;
                }

                //SockIOPool pool = SockIOPool.GetInstance();
                SockIOPool pool = SockIOPool.GetInstance(GetInstanceName);
                pool.SetServers(serverlist);
                pool.InitConnections = 3;
                pool.MinConnections = 3;
                pool.MaxConnections = 6;

                //pool.MaxIdle = 1000 * 60 * 60 * 1;

                pool.SocketConnectTimeout = 1000;
                pool.SocketTimeout = 3000;

                pool.MaintenanceSleep = 3000;
                pool.Failover = true;

                pool.Nagle = false;
                pool.Initialize();

                cache = new MemcachedClient();
                cache.PoolName = GetInstanceName;
                cache.EnableCompression = false;

                if (_enableLog)
                {
                    LogHelper.LogInfo(string.Format("◆缓存基本配置结束 InstanceName:{0} GetHashCode:{1}◆", GetInstanceName, cache.GetHashCode()));
                }
            }
        }

        private void ShutdownCache()
        {
            if (_enableLog)
            {
                LogHelper.LogInfo(string.Format("◇缓存 ShutdownCache 进程连接释放◇"));
            }
            string GetInstanceName = string.Format(_Format_NAME, _CacheName);
            //SockIOPool pool = SockIOPool.GetInstance();
            SockIOPool pool = SockIOPool.GetInstance(GetInstanceName);
            if (pool != null) pool.Shutdown();

            //CacheState();
        }

        private void Disconnect()
        {
            if (_enableLog)
            {
                LogHelper.Log(string.Format("◇缓存 Disconnect 连接释放◇"));
            }
            string GetInstanceName = string.Format(_Format_NAME, _CacheName);
            SockIOPool pool = SockIOPool.GetInstance(GetInstanceName);
            //SockIOPool pool = SockIOPool.GetInstance();
            if (pool != null) pool.Disconnect();
        }


        #endregion


        #region 实现接口

        /// <summary>
        /// 是否使用缓存
        /// </summary>
        public bool IsCache()
        {
            return _enableCache;
        }

        public void ReleaseConnection()
        {
            ShutdownCache();
        }

        public void DeltelCache()
        {
            string key = GetDeltelCacheName();
            int count = cache.DeleteCaCheName(key);
            if (_enableLog)
            {
                LogHelper.Log(string.Format("◆缓存 删除缓存:{0} {1}个◆", _CacheName, count));
            }
        }

        public T Get<T>(string key)
        {
            return GetValue<T>(GetKeyStr(key));
        }

        public List<T> GetObjectsByKey<T>(List<string> key)
        {
            if (_enableCache)
            {
                List<T> listt = null;
                string[] keylist = new string[key.Count];
                for (int i = 0, count = key.Count; i < count; i++)
                {
                    keylist[i] = GetKeyStr(key[i]);
                }

                object[] ValueList = cache.GetMultipleArray(keylist);
                if (ValueList != null)
                {
                    listt = new List<T>();
                    foreach (var val in ValueList)
                    {
                        if (val != null)
                        {
                            listt.Add(CacheCommon.StringToObj<T>(val.ToString()));
                        }
                    }
                }
                return listt;
            }
            else
            {
                return null;
            }

        }


        public Dictionary<string, T> GetKeyObjectsByKey<T>(List<string> key)
        {
            if (_enableCache)
            {
                Dictionary<string, T> resultlist = null;
                Hashtable ha = null;
                if ((key != null) && (key.Count > 0))
                {
                    string[] keys = new string[key.Count];
                    for (int i = 0, count = key.Count; i < count; i++)
                    {
                        keys[i] = GetKeyStr(key[i]);
                    }

                    ha = cache.GetMultiple(keys);
                    if (ha != null)
                    {
                        resultlist = new Dictionary<string, T>();
                        bool obj = false;

                        for (int i = 0, count = keys.Length; i < count; i++)
                        {
                            obj = ha.ContainsKey(keys[i]);
                            if (obj)
                            {
                                resultlist.Add(key[i], CacheCommon.StringToObj<T>(ha[keys[i]].ToString()));
                            }
                        }
                    }
                }

                return resultlist;
            }
            else
            {
                return null;
            }
        }



        public void Remove(string key)
        {
            if (_enableCache)
            {
                cache.Delete(GetKeyStr(key));
            }
        }

        public void Remove(List<string> key)
        {
            if ((key != null) && (key.Count > 0))
            {
                foreach (string k in key)
                {
                    Remove(k);
                }
            }
        }


        public void Put(string key, object value)
        {
            Put(key, value, _DEFAULT_MINUTES);
        }

        public void Put(string key, object value, int Seconds)
        {
            if ((_enableCache) && (value != null))
            {
                SaveValue(GetKeyStr(key), value, Seconds);
            }
        }





        public bool Exists(string key)
        {
            if (_enableCache)
            {
                object obj = cache.Get(GetKeyStr(key));
                if (obj != null)
                {
                    return true;
                }
                return false;
            }
            else
            {
                return false;
            }
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 转化Key为MemCache实际存储的KEY
        /// </summary>
        /// <param name="key">KEY</param>
        /// <param name="region">区域</param>
        /// <returns></returns>
        private string GetKeyStr(string key)
        {
            string result = string.Format("[{0}]{1}", _CacheName, key);
            return result;

        }

        private string RemoveKeyStr(string key)
        {
            string result = key.Replace(string.Format("[{0}]", _CacheName), "");
            return result;
        }

        private string GetDeltelCacheName()
        {
            string result = string.Format("[{0}]", _CacheName);
            return result;
        }



        /// <summary>
        /// 保存数据到缓存服务器
        /// </summary>
        /// <param name="key">处理过的KEY</param>
        /// <param name="value">值</param>
        /// <param name="Seconds">保存时间</param>
        /// <param name="region">区域</param>
        private void SaveValue(string key, object value, int Seconds)
        {
            if (_enableCache)
            {
                if (Seconds == 0)
                {
                    Seconds = _DEFAULT_MINUTES;
                }
                DateTime timespan = DateTime.Now.AddSeconds(Seconds);

                string values = CacheCommon.ObjToString(value);

                cache.Set(key, values, timespan);
            }
        }

        /// <summary>
        /// 从缓存服务器得到值
        /// </summary>
        /// <typeparam name="T">值</typeparam>
        /// <param name="key">处理过的KEY</param>
        /// <returns></returns>
        private T GetValue<T>(string key)
        {
            object obj = GetObjValue(key);
            if (obj != null)
            {
                if (_enableLog)
                {
                    LogHelper.LogInfo(string.Format("★Key:{0} 找到缓存", key));
                }
                return CacheCommon.StringToObj<T>(obj.ToString());
            }
            else
            {
                if (_enableLog)
                {
                    if (_enableCache)
                    {
                        LogHelper.LogInfo(string.Format("☆Key:{0} 未找到缓存", key));
                    }
                }
                //return null;
                return default(T);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private object GetObjValue(string key)
        {
            if (_enableCache)
            {
                return cache.Get(key);
            }
            else
            {
                return null;
            }
        }



        #endregion

        #region 出错处理

        /// <summary>
        /// 判断缓存服务器是否可以使用
        /// </summary>
        private void CheckError()
        {
            string key = "[CheckError_error]";
            string value = "[CheckError_error]";
            cache.Set(key, value, DateTime.Now.AddMinutes(1));
            object obj = cache.Get(key);
            if (obj == null)
            {
                ShutdownCache();
                throw new NotImplementedException("Memcached 缓存服务器出现异常,已经切换到无缓存状态!");
            }

        }

        #endregion



    }
}
